using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
#if MYCODE
using BepuUtilities.Vectors;
#else
using System.Numerics;
#endif
namespace BepuUtilities.Memory
{
    /// <summary>
    /// 创建固定内存块以供跨区使用的非托管内存池。
    /// </summary>
    /// <remarks>This currently works by allocating large managed arrays and pinning them under the assumption that they'll end up in the large object heap.</remarks>
    public class BufferPool : IUnmanagedMemoryPool, IDisposable
    {
        unsafe struct Block
        {
            public byte[] Array;
            public GCHandle Handle;
            public byte* Pointer;

            public Block(int blockSize)
            {
                // 虽然运行时确实有一些对齐保证,但我们避免了运行时可能更改(或另一个运行时正在使用)的可能性,
                // 或者运行库没有与足够大的大小对齐,无法容纳宽SIMD类型。我怀疑联合特种部队使用不结盟运动的倾向
                // 不管指令如何,现代处理器在未对齐指令上的性能将使这一点基本无关紧要,但它几乎是零成本。
                // 来自挡路的子分配将始终出现在幂2边界上,因此子分配违反此对齐的唯一方式是
                // 子分配比对齐小-在这种情况下,它不需要对齐那么宽。另外,由于路线和
                // 子分配都是幂2大小的,它们不会不同步。
                int alignment = Vector<float>.Count * sizeof(float);
                Array = new byte[blockSize + alignment];
                Handle = GCHandle.Alloc(Array, GCHandleType.Pinned);
                Pointer = (byte*)Handle.AddrOfPinnedObject();
                var mask = alignment - 1;
                var offset = (uint)Pointer & mask;
                Pointer += alignment - offset;
            }


            public byte* Allocate(int indexInBlock, int suballocationSize)
            {
                Debug.Assert(Allocated);
                Debug.Assert(Pinned);
                Debug.Assert(indexInBlock >= 0 && indexInBlock * suballocationSize < Array.Length);
                return Pointer + indexInBlock * suballocationSize;
            }

            public bool Allocated
            {
                get
                {
                    return Array != null;
                }
            }

            public bool Pinned
            {
                get
                {
                    return Array != null && Handle.IsAllocated;
                }
                set
                {

                    Debug.Assert(Array != null);
                    if (value)
                    {
                        Debug.Assert(!Handle.IsAllocated);
                        Handle = GCHandle.Alloc(Array);
                        Pointer = (byte*)Handle.AddrOfPinnedObject();
                    }
                    else
                    {
                        Debug.Assert(Handle.IsAllocated);
                        Handle.Free();
                        Pointer = null;
                    }
                }
            }

            /// <summary>
            /// 取消固定并删除对基础数组的引用。
            /// </summary>
            public void Clear()
            {
                Debug.Assert(Array != null);
                // 如果我们支持取消固定,则不能保证数组实际上是固定的。
                if (Handle.IsAllocated)
                {
                    Pinned = false;
                }
                Array = null;
            }

        }

        struct PowerPool
        {
            public Block[] Blocks;
            /// <summary>
            /// 此电源级别可用的插槽池。
            /// </summary>
            public ManagedIdPool Slots;
#if DEBUG
            internal HashSet<int> outstandingIds;
#if LEAKDEBUG
            internal Dictionary<string, HashSet<int>> outstandingAllocators;
#endif
#endif

            public readonly int SuballocationsPerBlock;
            public readonly int SuballocationsPerBlockShift;
            public readonly int SuballocationsPerBlockMask;
            public readonly int Power;
            public readonly int SuballocationSize;
            public readonly int BlockSize;
            public int BlockCount;

            internal const int IdPowerShift = 26;

            public PowerPool(int power, int minimumBlockSize, int expectedPooledCount)
            {
                Power = power;
                SuballocationSize = 1 << power;
                BlockSize = Math.Max(SuballocationSize, minimumBlockSize);
                Slots = new ManagedIdPool(expectedPooledCount);
                SuballocationsPerBlock = BlockSize / SuballocationSize;
                SuballocationsPerBlockShift = SpanHelper.GetContainingPowerOf2(SuballocationsPerBlock);
                SuballocationsPerBlockMask = (1 << SuballocationsPerBlockShift) - 1;
                Blocks = new Block[1];
                BlockCount = 0;

#if DEBUG
                outstandingIds = new HashSet<int>();
#if LEAKDEBUG
                outstandingAllocators = new Dictionary<string, HashSet<int>>();
#endif
#endif
            }

            public void EnsureCapacity(int capacity)
            {
                var neededBlockCount = (int)Math.Ceiling((double)capacity / BlockSize);
                if (BlockCount < neededBlockCount)
                {
                    if (neededBlockCount > Blocks.Length)
                        Array.Resize(ref Blocks, neededBlockCount);
                    for (int i = BlockCount; i < neededBlockCount; ++i)
                    {
                        Blocks[i] = new Block(BlockSize);
                    }
                    BlockCount = neededBlockCount;
                }

            }

            public unsafe byte* GetStartPointerForSlot(int slot)
            {
                var blockIndex = slot >> SuballocationsPerBlockShift;
                var indexInBlock = slot & SuballocationsPerBlockMask;
                return Blocks[blockIndex].Pointer + indexInBlock * SuballocationSize;
            }

            public unsafe void Take(out RawBuffer buffer)
            {
                var slot = Slots.Take();
                var blockIndex = slot >> SuballocationsPerBlockShift;
                if (blockIndex >= Blocks.Length)
                {
                    Array.Resize(ref Blocks, 1 << SpanHelper.GetContainingPowerOf2(blockIndex + 1));
                }
                if (blockIndex >= BlockCount)
                {
#if DEBUG
                    for (int i = 0; i < blockIndex; ++i)
                    {
                        Debug.Assert(Blocks[i].Allocated, "If a block index is found to exceed the current block count, then every block preceding the index should be allocated.");
                    }
#endif
                    BlockCount = blockIndex + 1;
                    Debug.Assert(!Blocks[blockIndex].Allocated);
                    Blocks[blockIndex] = new Block(BlockSize);
                }

                var indexInBlock = slot & SuballocationsPerBlockMask;
                buffer = new RawBuffer(Blocks[blockIndex].Allocate(indexInBlock, SuballocationSize), SuballocationSize, (Power << IdPowerShift) | slot);
                Debug.Assert(buffer.Id >= 0 && Power >= 0 && Power < 32, "Slot/power should be safely encoded in a 32 bit integer.");
#if DEBUG
                const int maximumOutstandingCount = 1 << 26;
                Debug.Assert(outstandingIds.Count < maximumOutstandingCount,
                    $"Do you actually truly really need to have {maximumOutstandingCount} allocations taken from this power pool, or is this a memory leak?");
                Debug.Assert(outstandingIds.Add(slot), "Should not be able to request the same slot twice.");
#if LEAKDEBUG
                var allocator = new StackTrace().ToString();
                if (!outstandingAllocators.TryGetValue(allocator, out var idsForAllocator))
                {
                    idsForAllocator = new HashSet<int>();
                    outstandingAllocators.Add(allocator, idsForAllocator);
                }
                Debug.Assert(idsForAllocator.Count < (1 << 25), "Do you actually have that many allocations for this one allocator?");
                idsForAllocator.Add(slot);
#endif
#endif
            }

            [Conditional("DEBUG")]
            internal unsafe void ValidateBufferIsContained(ref RawBuffer buffer)
            {
                // 有很多方法可以把这件事搞砸。试着钓到尽可能多的鱼！
                var slotIndex = buffer.Id & ((1 << IdPowerShift) - 1);
                var blockIndex = slotIndex >> SuballocationsPerBlockShift;
                var indexInAllocatorBlock = slotIndex & SuballocationsPerBlockMask;
                Debug.Assert(buffer.Length <= SuballocationSize,
                  "A buffer taken from a pool should have a specific size.");
                Debug.Assert(blockIndex >= 0 && blockIndex < BlockCount,
                    "The block pointed to by a returned buffer should actually exist within the pool.");
                var memoryOffset = buffer.Memory - Blocks[blockIndex].Pointer;
                Debug.Assert(memoryOffset >= 0 && memoryOffset < Blocks[blockIndex].Array.Length,
                    "If a raw buffer points to a given block as its source, the address should be within the block's memory region.");
                Debug.Assert(Blocks[blockIndex].Pointer + indexInAllocatorBlock * SuballocationSize == buffer.Memory,
                    "The implied address of a buffer in its block should match its actual address.");
                Debug.Assert(buffer.Length + indexInAllocatorBlock * SuballocationSize <= Blocks[blockIndex].Array.Length,
                    "The extent of the buffer should fit within the block.");
            }

            public unsafe void Return(int slotIndex)
            {
#if DEBUG 
                Debug.Assert(outstandingIds.Remove(slotIndex),
                    "This buffer id must have been taken from the pool previously.");
#if LEAKDEBUG
                bool found = false;
                foreach (var pair in outstandingAllocators)
                {
                    if (pair.Value.Remove(slotIndex))
                    {
                        found = true;
                        if (pair.Value.Count == 0)
                        {
                            outstandingAllocators.Remove(pair.Key);
                            break;
                        }
                    }
                }
                Debug.Assert(found, "Allocator set must contain the buffer id.");
#endif
#endif
                Slots.Return(slotIndex);
            }

            public void Clear()
            {
#if DEBUG
                // 我们将假设调用方了解未完成的缓冲区已失效,因此不应再次返回。
                outstandingIds.Clear();
#if LEAKDEBUG
                outstandingAllocators.Clear();
#endif
#endif
                for (int i = 0; i < BlockCount; ++i)
                {
                    Blocks[i].Clear();
                }
                Slots.Clear();
                BlockCount = 0;
            }

        }

        private PowerPool[] pools = new PowerPool[SpanHelper.MaximumSpanSizePower + 1];
        private int minimumBlockSize;

        /// <summary>
        /// 创建新的缓冲池。
        /// </summary>
        /// <param name="minumBlockAllocationSize">单个挡路分配的最小大小。一定是2的幂。
        /// 单个分配大于最小值的池将使用容纳一个元素所需的最小值。
        /// 缓冲区将从块中再分配。
        /// 使用大于大对象堆截止值的值(在编写本文时,微软运行时为85000字节)
        /// 以避免干扰世代垃圾回收。</param>
        /// <param name="expectedPooledResourceCount">要为其预分配引用空间的子分配数量。
        /// 这不会预分配实际块,而只是预分配容纳池中等待的引用的空间。</param>
        public BufferPool(int minimumBlockAllocationSize = 131072, int expectedPooledResourceCount = 16)
        {
            if (((minimumBlockAllocationSize - 1) & minimumBlockAllocationSize) != 0)
                throw new ArgumentException("Block allocation size must be a power of 2.");
            minimumBlockSize = minimumBlockAllocationSize;
            for (int power = 0; power <= SpanHelper.MaximumSpanSizePower; ++power)
            {
                pools[power] = new PowerPool(power, minimumBlockSize, expectedPooledResourceCount);
            }
        }

        /// <summary>
        /// 确保与给定电源关联的池至少具有一定的容量(以字节为单位)。
        /// </summary>
        /// <param name="byteCount">电源池需要的最小字节数。</param>
        /// <param name="power">与要检查的池关联的电源。</param>
        public void EnsureCapacityForPower(int byteCount, int power)
        {
            SpanHelper.ValidatePower(power);
            ValidatePinnedState(true);
            pools[power].EnsureCapacity(byteCount);
        }

        /// <summary>
        /// 获取为电源分配的容量。
        /// </summary>
        /// <param name="power">要检查的电源。</param>
        /// <return>指定电源的分配容量。</return>
        public int GetCapacityForPower(int power)
        {
            SpanHelper.ValidatePower(power);
            return pools[power].BlockCount * pools[power].BlockSize;
        }

        /// <summary>
        /// 获取足够大的缓冲区,以包含多个字节。容量可能大于请求的容量。
        /// </summary>
        /// <param name="count">所需的缓冲区最小容量(字节)。</param>
        /// <param name="buffer">可以容纳字节的缓冲区。</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void TakeAtLeast(int count, out RawBuffer buffer)
        {
            TakeForPower(SpanHelper.GetContainingPowerOf2(count), out buffer);
        }

        /// <summary>
        /// 从池中获取请求大小的缓冲区。
        /// </summary>
        /// <param name="count">所需的缓冲区容量(以字节为单位)。</param>
        /// <param name="buffer">请求大小的缓冲区。</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void Take(int count, out RawBuffer buffer)
        {
            TakeAtLeast(count, out buffer);
            buffer.Length = count;
        }

        /// <summary>
        /// 获取足够大的缓冲区,以包含多个给定类型的元素。容量可能大于请求的容量。
        /// </summary>
        /// <typeparam name="T">缓冲区中元素的类型。</typeparam>
        /// <param name="count">所需的类型化元素中缓冲区的最小容量。</param>
        /// <param name="buffer">缓冲区大小足以包含请求的元素数。</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void TakeAtLeast<T>(int count, out Buffer<T> buffer) where T : unmanaged
        {
            // 避免返回零长度范围,因为1byte/Unsafe.SizeOf<T>()恰好为零。
            if (count == 0)
                count = 1;
            TakeAtLeast(count * Unsafe.SizeOf<T>(), out var rawBuffer);
            buffer = rawBuffer.As<T>();
        }

        /// <summary>
        /// 从池中获取请求大小的类型化缓冲区。
        /// </summary>
        /// <typeparam name="T">缓冲区中实例的类型。</typeparam>
        /// <param name="count">类型化元素中缓冲区的所需容量。</param>
        /// <param name="buffer">键入的请求大小的缓冲区。</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void Take<T>(int count, out Buffer<T> buffer) where T : unmanaged
        {
            TakeAtLeast(count, out buffer);
            buffer.length = count;
        }

        /// <summary>
        /// 取一个足够大的缓冲区,以包含幂给出的字节数,其中字节数是2^次方。
        /// </summary>
        /// <param name="count">应以指数形式放入缓冲区的字节数,其中字节数为2^次方。</param>
        /// <param name="buffer">可以容纳字节的缓冲区。</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void TakeForPower(int power, out RawBuffer buffer)
        {
            ValidatePinnedState(true);
            Debug.Assert(power >= 0 && power <= SpanHelper.MaximumSpanSizePower);
            pools[power].Take(out buffer);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        internal static void DecomposeId(int bufferId, out int powerIndex, out int slotIndex)
        {
            powerIndex = bufferId >> PowerPool.IdPowerShift;
            slotIndex = bufferId & ((1 << PowerPool.IdPowerShift) - 1);
        }

        /// <summary>
        /// 按id将缓冲区返回到池。
        /// </summary>
        /// <param name="buffer">返回池的缓冲区。</param>
        /// <remarks>Typed buffer pools zero out the passed-in buffer by convention.
        /// 这样成本很低,并且避免了各种各样的错误(直接或通过强制快速故障)。为了保持一致性,BufferPool.Return做了同样的事情。
        /// 此"不安全"重载应仅在有理由绕过CLEAR的情况下使用;命名旨在阻止随意使用。</MARKEMS>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public unsafe void ReturnUnsafely(int id)
        {
            ValidatePinnedState(true);
            DecomposeId(id, out var powerIndex, out var slotIndex);
            pools[powerIndex].Return(slotIndex);
        }

        /// <summary>
        /// 将缓冲区返回到池。
        /// </summary>
        /// <param name="buffer">返回池的缓冲区。</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public unsafe void Return(ref RawBuffer buffer)
        {
#if DEBUG
            DecomposeId(buffer.Id, out var powerIndex, out var slotIndex);
            pools[powerIndex].ValidateBufferIsContained(ref buffer);
#endif
            ReturnUnsafely(buffer.Id);
            buffer = default;
        }
        /// <summary>
        /// 将缓冲区返回到池。
        /// </summary>
        /// <param name="buffer">返回池的缓冲区。</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public unsafe void Return<T>(ref Buffer<T> buffer) where T : unmanaged
        {
            ReturnUnsafely(buffer.Id);
            buffer = default;
        }

        // 调整大小并不是特别聪明。他们在重新分配方面比他们需要的更积极,但是
        // 假设只有在已经知道需要调整大小时才会使用它们。
        /// <summary>
        /// 将缓冲区大小调整为包含目标大小的池中可用的最小大小。将元素子集复制到新缓冲区。
        /// 最终缓冲区大小至少与目标大小一样大,并且可能更大。
        /// </summary>
        /// <param name="buffer">要调整大小的缓冲区引用。</param>
        /// <param name="targetSize">要调整缓冲区大小的字节数。</param>
        /// <param name="copy Count">要从旧缓冲区复制到新缓冲区的字节数。</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public unsafe void ResizeToAtLeast(ref RawBuffer buffer, int targetSize, int copyCount)
        {
            Debug.Assert(copyCount <= buffer.Length, "Can't copy more than the capacity of the buffer.");
            Debug.Assert(copyCount <= targetSize, "Can't copy more than the target size.");
            // 仅当新大小实际上不同于当前大小时才执行任何操作。
            targetSize = 1 << (SpanHelper.GetContainingPowerOf2(targetSize));
            if (buffer.Allocated)
            {
                DecomposeId(buffer.Id, out var powerIndex, out var slotIndex);
                var currentSize = 1 << powerIndex;
                if (currentSize != targetSize || pools[powerIndex].GetStartPointerForSlot(slotIndex) != buffer.Memory)
                {
                    TakeAtLeast(targetSize, out var newBuffer);
                    Buffer.MemoryCopy(buffer.Memory, newBuffer.Memory, buffer.Length, copyCount);
                    pools[powerIndex].Return(slotIndex);
                    buffer = newBuffer;
                }
                else
                {
                    // 虽然分配大小等于目标大小,但缓冲区可能不等于目标大小。
                    // 幸运的是,如果分配大小保持不变,并且缓冲区开始位置在其原始位置,我们可以跳过任何工作。
                    // (有了更多的工作,您可以"向后"扩展,我们只是没有麻烦,因为这无论如何都是非常罕见的。
                    // 类型化的代码路径根本不会费心去做这件事,这很好。)
                    buffer.Length = targetSize;
                }
            }
            else
            {
                // 没有要退回或复印的东西。
                TakeAtLeast(targetSize, out buffer);
            }
        }

        /// <summary>
        /// 将缓冲区大小调整为目标大小。将元素子集复制到新缓冲区。
        /// </summary>
        /// <param name="buffer">要调整大小的缓冲区引用。</param>
        /// <param name="targetSize">要调整缓冲区大小的字节数。</param>
        /// <param name="copy Count">要从旧缓冲区复制到新缓冲区的字节数。</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public unsafe void Resize(ref RawBuffer buffer, int targetSize, int copyCount)
        {
            ResizeToAtLeast(ref buffer, targetSize, copyCount);
            buffer.Length = targetSize;
        }

        /// <summary>
        /// 将类型化缓冲区大小调整为包含目标大小的池中可用的最小大小。将元素子集复制到新缓冲区。
        /// 最终缓冲区大小至少与目标大小一样大,并且可能更大。
        /// </summary>
        /// <typeparam name="T">要调整大小的缓冲区类型。</typeparam>
        /// <param name="buffer">要调整大小的缓冲区引用。</param>
        /// <param name="targetSize">要调整缓冲区大小的元素数。</param>
        /// <param name="CopyCount">要从旧缓冲区复制到新缓冲区的元素数。</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void ResizeToAtLeast<T>(ref Buffer<T> buffer, int targetSize, int copyCount) where T : unmanaged
        {
            // 仅当新大小实际上不同于当前大小时才执行任何操作。
            Debug.Assert(copyCount <= targetSize && copyCount <= buffer.Length, "Can't copy more elements than exist in the source or target buffers.");
            targetSize = GetCapacityForCount<T>(targetSize);
            if (buffer.Length != targetSize) // 请注意,我们不检查已分配状态-对于缓冲区,长度0与未分配的长度相同。
            {
                TakeAtLeast(targetSize, out Buffer<T> newBuffer);
                if (buffer.Length > 0)
                {
                    // 不必费心从空缓冲区复制或重新合用空缓冲区。它们未初始化。
                    buffer.CopyTo(0, newBuffer, 0, copyCount);
                    ReturnUnsafely(buffer.Id);
                }
                else
                {
                    Debug.Assert(copyCount == 0, "Should not be trying to copy elements from an empty span.");
                }
                buffer = newBuffer;
            }
        }


        /// <summary>
        /// 将缓冲区大小调整为目标大小。将元素子集复制到新缓冲区。
        /// </summary>
        /// <typeparam name="T">要调整大小的缓冲区类型。</typeparam>
        /// <param name="buffer">要调整大小的缓冲区引用。</param>
        /// <param name="targetSize">要调整缓冲区大小的元素数。</param>
        /// <param name="CopyCount">要从旧缓冲区复制到新缓冲区的元素数。</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void Resize<T>(ref Buffer<T> buffer, int targetSize, int copyCount) where T : unmanaged
        {
            ResizeToAtLeast(ref buffer, targetSize, copyCount);
            buffer.length = targetSize;
        }

        [Conditional("LEAKDEBUG")]
        void ValidatePinnedState(bool pinned)
        {
            for (int i = 0; i < pools.Length; ++i)
            {
                var pool = pools[i];
                for (int j = 0; j < pool.BlockCount; ++j)
                {
                    Debug.Assert(pool.Blocks[j].Pinned == pinned, $"For this operation, all blocks must share the same pinned state of {pinned}.");
                }
            }
        }

        [Conditional("DEBUG")]
        public void AssertEmpty()
        {
#if DEBUG
            for (int i = 0; i < pools.Length; ++i)
            {
                var pool = pools[i];
                if (pool.outstandingIds.Count > 0)
                {
                    Debug.WriteLine($"Power pool {i} contains allocations.");
#if LEAKDEBUG
                    foreach (var allocator in pool.outstandingAllocators)
                    {
                        Debug.WriteLine($"{allocator.Key}   ALLOCATION COUNT: {allocator.Value.Count}");
                    }
#endif
                    Debug.Assert(pool.outstandingIds.Count == 0);
                }
            }
#endif
        }

        /// <summary>
        /// 获取或设置是否固定BufferPool的支持资源。如果内部没有分配任何块,则返回TRUE。
        /// 将其设置为false将使所有未完成的指针无效,并且在解除锁定时获取或返回缓冲区的任何尝试都将失败(尽管不一定立即失败)。
        /// 取消固定时唯一有效的操作是将固定设置为true并清除池。
        /// </summary>
        public bool Pinned
        {
            get
            {
                // 如果不存在任何块,我们将其称为固定-这是默认状态。
                bool pinned = true;
                for (int i = 0; i < pools.Length; ++i)
                {
                    if (pools[i].BlockCount > 0)
                    {
                        pinned = pools[i].Blocks[0].Pinned;
                        break;
                    }
                }
                ValidatePinnedState(pinned);
                return pinned;
            }
            set
            {
                void ChangePinnedState(bool pinned)
                {
                    for (int i = 0; i < pools.Length; ++i)
                    {
                        var pool = pools[i];
                        for (int j = 0; j < pool.BlockCount; ++j)
                        {
                            pool.Blocks[j].Pinned = pinned;
                        }
                    }
                }
                if (value)
                {
                    if (!Pinned)
                    {
                        ChangePinnedState(true);
                    }
                }
                else
                {
                    if (Pinned)
                    {
                        ChangePinnedState(false);
                    }
                }
            }
        }

        /// <summary>
        /// 取消固定并删除对所有内存的引用。任何未完成的缓冲区都将以静默方式失效。
        /// </summary>
        public void Clear()
        {
            for (int i = 0; i < pools.Length; ++i)
            {
                pools[i].Clear();
            }
        }

        void IDisposable.Dispose()
        {
            Clear();
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static int GetCapacityForCount<T>(int count)
        {
            if (count == 0)
                count = 1;
            return (1 << SpanHelper.GetContainingPowerOf2(count * Unsafe.SizeOf<T>())) / Unsafe.SizeOf<T>();
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        int IUnmanagedMemoryPool.GetCapacityForCount<T>(int count)
        {
            return GetCapacityForCount<T>(count);
        }

#if DEBUG
        ~BufferPool()
        {
            var totalBlockCount = 0;
            for (int i = 0; i < pools.Length; ++i)
            {
                totalBlockCount += pools[i].BlockCount;
            }
            // 如果挡路计数为零,PINTED只返回TRUE,因为这是默认值。如果存在非零数量的块,则必须显式取消固定它们
            // 以使终结器有效。
            Debug.Assert(totalBlockCount == 0 || !Pinned, "Memory leak warning! Don't let a buffer pool die without unpinning it!");
        }
#endif

    }
}
